﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using CompileApp.Models;
using CompileApp.windows;
using Microsoft.Win32;


namespace CompileApp;

public partial class SyntaxProgram : UserControl
{
    
    private ObservableCollection<DealDetail> _dealDetails = new();
    public SyntaxProgram()
    {
        InitializeComponent();

        TokenFileButton.Click += ReadTokenFileContent;
        SourceFileButton.Click += ReadSourceFileContent;
        StartTableButton.Click += (sender, args) =>
        {
            if (_parse == null)
            {
                MessageBox.Show("请先输入上下文无关文法");
            }
            else
            {
                Lr1Table lr1Table = new Lr1Table(_parse);
                lr1Table.Show();
            }
        };
        StartButton.Click += StartGenerate;
        // ResultTable.Columns.Add(new DataGridTextColumn(){Header = "状态栈", Width = 100, Binding = new Binding("State")});
        // ResultTable.Columns.Add(new DataGridTextColumn(){Header = "输入串", Width = 100, Binding = new Binding("InputStr")});
        // ResultTable.Columns.Add(new DataGridTextColumn(){Header = "当前字符串", Width = 100, Binding = new Binding("CurrentStr")});
        // ResultTable.Columns.Add(new DataGridTextColumn(){Header = "描述", Width = 300, Binding = new Binding("Message")});
        ResultTable.ItemsSource = _dealDetails;
        ResultTable.AutoGenerateColumns = true;
    }

    private Parse? _parse;
    private Stack<string> _states = new();
    private Stack<Token> _currentStr = new();
    private Stack<Token> _inputStr = new();

    private void ReadSourceFileContent(object sender, RoutedEventArgs args)
    {
        TextBox? content = SourceFileContent;

        OpenFileDialog fileDialog = new OpenFileDialog();
        fileDialog.Title = "请选择文件";
        fileDialog.Filter = "所有文件(*.*)|*.*";
        if (fileDialog.ShowDialog() ?? false)
        {
            content.Clear();
            string fileName = fileDialog.FileName;
            StreamReader reader = new StreamReader(fileName);
            string? line = reader.ReadLine();
            while (line != null)
            {
                content.AppendText($"{line}\n");
                line = reader.ReadLine();
            }

            reader.Close();
            _parse = new(content.Text);
        }
        else
        {
            // MessageBox.Show("已取消!");
        }
    }

    private void ReadTokenFileContent(object sender, RoutedEventArgs args)
    {
        TextBox? content = TokenFileContent;

        OpenFileDialog fileDialog = new OpenFileDialog();
        fileDialog.Title = "请选择文件";
        fileDialog.Filter = "所有文件(*.*)|*.*";
        if (fileDialog.ShowDialog() ?? false)
        {
            content.Clear();
            string fileName = fileDialog.FileName;
            StreamReader reader = new StreamReader(fileName);
            string? line = reader.ReadLine();
            while (line != null)
            {
                content.AppendText($"{line}\n");
                line = reader.ReadLine();
            }

            reader.Close();
        }
        else
        {
            // MessageBox.Show("已取消!");
        }
    }

    private void StartGenerate(object sender, RoutedEventArgs args)
    {
        if (_parse == null)
        {
            MessageBox.Show("请输入文法");
            return;
        }

        if (TokenFileContent.Text.Equals(""))
        {
            MessageBox.Show("请输入Token文件");
            return;
        }


        var list = TokenFileContent.Text.Split("\n", StringSplitOptions.RemoveEmptyEntries);
        _states.Clear();
        _currentStr.Clear();
        _inputStr.Clear();
        _dealDetails.Clear();
        ResultBox.Clear();

        _states.Push("0");
        _currentStr.Push(new Token(-1, "终止符", "#"));
        _inputStr.Push(new Token(-1, "终止符", "#"));
        List<string> sList = new();
        // ResultBox.Text = "";


        for (int i = list.Length - 1; i >= 0; i--)
        {
            var item = Utils.GetToken(list[i]);
            if (item.Value.Equals(""))
            {
                continue;
            }
            _inputStr.Push(item);
        }

        while (_inputStr.Any())
        {
            var item = _inputStr.Pop();
            var state = _states.Peek();

            var tuple = new Tuple<string, string>(state, Utils.GetTokenType(item));
            // var tuple = new Tuple<string, string>(state, item.Value);
            if (_parse.Action.ContainsKey(tuple))
            {
                var status = _parse.Action[tuple];
                if (status.GType == ActionType.Acc)
                {
                    // ResultBox.AppendText("该代码没有问题!");
                    _inputStr.Push(item);
                    _dealDetails.Add(DealDetail._getDealDetail(_states, _inputStr, _currentStr, "该代码没有问题!"));
                    ResultBox.AppendText("该代码没有问题!");
                    break;
                }
                else if (status.GType == ActionType.S)
                {
                    _states.Push(status.State);
                    _currentStr.Push(item);
                    // ResultBox.AppendText($"移进[{item.Value}]");
                    _dealDetails.Add(DealDetail._getDealDetail(_states, _inputStr, _currentStr, $"移进[{item.Value}]"));
                }
                else if (status.GType == ActionType.R)
                {
                    // ResultBox.AppendText("规约");
                    var message = "规约";
                    _inputStr.Push(item);
                    var rule = _parse.Rules[status.State];
                    for (int i = rule.RightItem.Count - 1; i >= 0; i--)
                    {
                        var str = _currentStr.Pop();
                        var tState = _states.Pop();
                        message += $"[{str.Value}]——";
                        // ResultBox.AppendText($"[{str.Value}]——");
                    }
                    
                    _currentStr.Push(new Token(item.Line, Constant.FindType(rule.LeftItem), rule.LeftItem));
                    _states.Push(_parse.Goto[new Tuple<string, string>(_states.Peek(), rule.LeftItem)]);
                    _dealDetails.Add(DealDetail._getDealDetail(_states, _inputStr, _currentStr, message));
                }
                // ResultBox.AppendText("\n");
            }
            else
            {
                // ResultBox.AppendText($"第{item.Line}行出现了一个错误,可能的原因是:\n不应该出现[{item.Value}],而应该");
                var message = $"第{item.Line}行出现了一个错误,可能的原因是:\n不应该出现[{item.Value}],而应该";
                foreach (var str in _parse.Edges[state])
                {
                    message += $"或者是[{str}]";
                    // ResultBox.AppendText($"或者是[{str}]");
                }
                _dealDetails.Add(DealDetail._getDealDetail(_states, _inputStr, _currentStr, message));
                ResultBox.AppendText(message);
                break;
            }
            
        }
    }
}

public class DealDetail
{
    public string State { get; set; }
    public string Message { get; set; }
    public string InputStr { get; set; }
    public string CurrentStr { get; set; }
    
    public DealDetail(string state, string inputStr, string currentStr, string message)
    {
        State = state;
        InputStr = inputStr;
        CurrentStr = currentStr;
        Message = message;
    }
    
    public static DealDetail _getDealDetail(Stack<string> states, Stack<Token> inputStr, Stack<Token> currentStr, string message)
    {
        var detail = new DealDetail("", "", "", message);
        var sList = new List<string>(states);
        sList.Reverse();
        detail.State = string.Join("-", sList);
        var iList = new List<Token>(inputStr);
        iList.Reverse();
        detail.InputStr = string.Join("-", iList.Select(x => x.Value));
        iList = new List<Token>(currentStr);
        iList.Reverse();
        detail.CurrentStr = string.Join("-", iList.Select(x => x.Value));
        return detail;
    }
}